package com.xpoint.backend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xpoint.backend.common.R;
import com.xpoint.backend.dto.DishDto;
import com.xpoint.backend.entity.Category;
import com.xpoint.backend.entity.Dish;
import com.xpoint.backend.entity.DishFlavor;
import com.xpoint.backend.mapper.DishMapper;
import com.xpoint.backend.service.CategoryService;
import com.xpoint.backend.service.DishFlavorService;
import com.xpoint.backend.service.DishService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.events.Event;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
//    分页查询
    public R<Page> findPage(Long page, Long pageSize, String name) {
//        创建分页对象
        Page<Dish> dishPage = new Page<>(page, pageSize);
//        创建条件构造器
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        编写SQL条件
        lambdaQueryWrapper.eq(name!=null&&name!="",Dish::getName,name);
        lambdaQueryWrapper.orderByDesc(Dish::getUpdateTime);
//        分页查询
        this.page(dishPage,lambdaQueryWrapper);
        /*
        * 这里还要查询菜品分类，因为当初菜品分类添加的时候是添加的ID，而且dish实体类中只有分类id*/
        Page<DishDto> dishDtoPage = new Page<>();
//        将dish（分页数据）拷贝给dishDto,因为dishDtoPage对象和dishPage对象的records（结果集）不一样，所以不能直接拷贝，所以过滤掉!
        BeanUtils.copyProperties(dishDtoPage,dishPage,"records");
//        获取dishPage分页对象的records，相当于一个实体对象
        List<Dish> records = dishPage.getRecords();
//        创建dishDtoList，存放dishDtos的records的数据
        List<DishDto> dishDtos = new ArrayList<>();
        for (Dish record : records) {
//            创建一个dishDto对象
            DishDto dishDto = new DishDto();
//            因为dishDto是继承的dish，这个遍历出来的record就是dish的一个实体类，可以复制给dishDto。
            BeanUtils.copyProperties(record,dishDto);
//            根据dish的id查询菜品分类！！！
            Long categoryId = record.getCategoryId();
            Category byId = categoryService.getById(categoryId);
//            将菜品分类的名称，存到dishDto中
            if (byId.getName()!=null&&byId.getName()!="") {
                dishDto.setCategoryName(byId.getName());
            }
//            dishDto存到list中
            dishDtos.add(dishDto);
        }
//        将list存入dishDtoPage的records中
        dishDtoPage.setRecords(dishDtos);
        if (dishPage!=null){
            return R.success(dishDtoPage);
        }
        return R.error("失败");
    }
    @Transactional
    @Override
//    添加菜品
    public R<String> addDish(DishDto dishDto) {
        if (dishDto!=null){
//            添加到dish表中
            boolean save = this.save(dishDto);
            if (save){
                List<DishFlavor> flavors = dishDto.getFlavors();
//                将接收到的Flavors表遍历。
                flavors = flavors.stream().map((item) -> {
//                    设置给Flavors表中设置当前dish的id。然后就可以连起来了。
                    item.setDishId(dishDto.getId());
                    return item;
                }).collect(Collectors.toList());
//                添加到dish_flavor表中
                dishFlavorService.saveBatch(flavors);
                return R.success("添加成功");
            }
            return R.error("添加失败");
        }
        return R.error("为空");
    }

    @Override
//    更新dish状态
    public R<String> updateDishStatus(Integer status, List<Long> ids) {
        if (status!=null && ids!=null){
//            一个存放菜品id和status的list
            List<Dish> dishList = new ArrayList<>();
//            LambdaUpdateWrapper<Dish> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
//            lambdaUpdateWrapper.in(Dish::getStatus,status);
            for (Long id : ids) {
//                遍历前端传过来的id
                Dish dish = new Dish();
//                在循环中创建对象,那样可以保证对象是单例的.
                dish.setId(id);
                dish.setStatus(status);
                dishList.add(dish);
            }
//            批量根据id更新操作
            boolean b = updateBatchById(dishList);
            if (b){
                return R.success("成功");
            }
        }
        return R.error("参数为空，操作失败");
    }

    @Override
//    批量删除
    public R<String> deleteBatchByIds(List<Long> id) {
//        System.out.println(id);
        if (id!=null){


            if (this.removeByIds(id)) {
                return R.success("删除成功");
            }
            return R.error("删除失败");
        }
        return R.error("空的");
    }

    @Override
//    根据id查询
    public R<DishDto> findByid(Long id) {
//        根据id查询dish（菜品）
        Dish dish = this.getById(id);
//        因为要查询的内容不单单有菜品，还有菜品口味，以及菜品分类。所以要返回dishDto对象
        DishDto dishDto = new DishDto();
//        将查询到的dish数据，复制给dishDto对象
        BeanUtils.copyProperties(dish,dishDto);
//        创建一个菜品口味的条件构造器
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
//        查询根据id查询菜品口味
        queryWrapper.eq(DishFlavor::getDishId,dish.getId());
//        执行list查询。
        List<DishFlavor> list = dishFlavorService.list(queryWrapper);
//        将查询的list结果存至Flavors(菜品口味)
        dishDto.setFlavors(list);

//        当前dish中的菜品分类id
        Long categoryId = dish.getCategoryId();
//        根据菜品分类id，查询菜品分类表，Category
        Category category = categoryService.getById(categoryId);
//        将Category对象的name，赋值给dishDto的categoryName属性
        dishDto.setCategoryName(category.getName());
        if (dishDto!=null){

            return R.success(dishDto);
        }
        return R.error("查询失败");
    }

    @Override
    public R<String> updateDish(DishDto dishDto) {
//        一、修改dish(菜品)表
        Dish dish = new Dish();
//        将dishDto类的属性复制给dish
        BeanUtils.copyProperties(dishDto,dish);
//      修改菜品分类，因为前端传过来的菜品分类ID是字段CategoryName，所以要把CategoryName强转给dish的CategoryId
        dish.setCategoryId(Long.valueOf(dishDto.getCategoryName()));
//        判断是否成功修改
        boolean dishSuccess = this.updateById(dish);

//        二、修改dishFlavor(菜品口味)表
//        先清空当前菜品的菜品口味数据
//          创建一个dishFlavor的条件构造器
        LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        条件：字段dishid=dish.getId()
        lambdaQueryWrapper.eq(DishFlavor::getDishId,dish.getId());
//        判断是否成功删除
        boolean remove = dishFlavorService.remove(lambdaQueryWrapper);

//        三、添加菜品口味
//        获取前端传过来的菜品id
        List<DishFlavor> flavors = dishDto.getFlavors();
//        遍历菜品口味
        boolean dishFlavorSuccess = false;
        if (flavors!=null) {
            for (DishFlavor flavor : flavors) {
    //            设置菜品口味中的dishId
                flavor.setDishId(dish.getId());
            }
//            判断是否成功添加
            dishFlavorSuccess = dishFlavorService.saveBatch(flavors);
        }

//        如果dish、remove、dishFlavor有一个修改成功就返回成功
        if (dishSuccess==true||remove==true||dishFlavorSuccess==true){
////            获取当前更新的分类id
//            Set keys = redisTemplate.keys(dishDto.getCategoryId() + "_" + dishDto.getStatus());
////            删除key,保证mysql与redis数据的一致性
//            redisTemplate.delete(keys);
            return R.success("成功");
        }

        return R.error("失败");
    }

    @Override
//    根据分类id，查询分类下的菜品
    public R<List<DishDto>> findCategoryById(Dish dish) {
//        这是要返回的对象
        List<DishDto> litsDishDto = null;
//        获取分类的id
        Long id = dish.getCategoryId();
//        获取菜品名称，这里是后台搜索功能的
        String name = dish.getName();
//        获取状态
        Integer status = dish.getStatus();

//        拼接成一个字符串用于查询Redis缓存里面的数据的
        String category = id+"_"+status;
//        查询redis
//        litsDishDto = (List<DishDto>) redisTemplate.opsForValue().get(category);
//        if (litsDishDto!=null&&litsDishDto.size()!=0){
////            如果redis数据存在，直接返回
//            return R.success(litsDishDto);
//        }
//        如果redis数据库不存在,则进行去mysql查询

//        判断如果id不为空，或者name不为空。这里的name是在管理端的搜索功能
        if (id!=null||StringUtils.isNotEmpty(name)) {
//        创建条件构造器
            LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        如果name不为空，就模糊查询dish表中的name=传参数过来的name
            lambdaQueryWrapper.like(StringUtils.isNotEmpty(name),Dish::getName,name);
//        如果id不为空，就查询id
            lambdaQueryWrapper.eq(Dish::getCategoryId,id);
//        状态为1的，也就是启售状态的
            lambdaQueryWrapper.eq(Dish::getStatus,1);
//          一、查询菜品
            List<Dish> list = list(lambdaQueryWrapper);
//           这里是要return的对象，有菜品和菜品分类名称，还有菜品口味
            litsDishDto = new ArrayList<>();
            for (Dish dish1 : list) {
                DishDto dishDto = new DishDto();
//                将菜品复制给dishDto对象
                BeanUtils.copyProperties(dish1,dishDto);
//                菜品id
                Long categoryId = dish1.getCategoryId();
//              二、根据id查询菜品分类
                Category dishId = categoryService.getById(categoryId);
//                将菜品分类名称赋值给Dto对象
                dishDto.setCategoryName(dishId.getName());

                // 三、查询根据菜品id查询菜品口味
                LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
                dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId,dish1.getId());
                List<DishFlavor> list1 = dishFlavorService.list(dishFlavorLambdaQueryWrapper);
                dishDto.setFlavors(list1);
                litsDishDto.add(dishDto);
            }
            if (litsDishDto!=null){
////                将对象保存到redis中
//                redisTemplate.opsForValue().set(category,litsDishDto,60, TimeUnit.MINUTES);
                return R.success(litsDishDto);
            }
        }
        return R.error("请输入响应信息");
    }
}
